import { reactive } from '@vue/reactivity'
import { computed, h, RendererElement, watch } from '@vue/runtime-core'
import { MediaHTMLAttributes } from '@vue/runtime-dom'
import { useStore } from 'vuex'
export type HTMLMediaProps = MediaHTMLAttributes
export interface HTMLMediaState {
  buffered: any[]
  duration: number
  paused: boolean
  muted: boolean
  time: number
  volume: number
}
export interface HTMLMediaControls {
  play: () => Promise<void> | void
  pause: () => void
  seek: (time: number) => void
  volume: (volume: number) => void
}
const createHTMLMediaHook = (tag: 'audio' | 'video') => {
  const hook = (elOrProps: HTMLMediaProps): [RendererElement, HTMLMediaState, HTMLMediaControls] => {
    const store = useStore()
    const props = elOrProps as HTMLMediaProps
    let isChange = false

    const state = reactive({
      buffered: [],
      duration: 0,
      time: 0,
      paused: true,
      muted: false,
      volume: 0.75,
    }) as HTMLMediaState
    const musicUrl = computed(() => store.state.playMusic.musicUrl)

    const wrapEvent = (userEvent: any, proxyEvent?: any) => {
      return (event: Event) => {
        try {
          proxyEvent && proxyEvent(event)
        } finally {
          userEvent && userEvent(event)
        }
      }
    }

    const onPlay = () => (state.paused = false)
    const onPause = () => (state.paused = true)
    const onReady = () => {
      // console.log('开始')
    }
    const updateTime = (e: any) => {
      // console.log('更新时间', e.target.currentTime)
      if (!isChange) {
        state.time = e.target.currentTime
      }
    }

    const element = h(tag, {
      src: musicUrl.value,
      volume: state.volume,
      ...props,
      onCanplay: onReady,
      onTimeupdate: updateTime,
      onPlay: wrapEvent(props.onPlay, onPlay),
      onPause: wrapEvent(props.onPause, onPause),
    } as any)
    let lockPlay = false
    const controls = {
      play: () => {
        const el = element.el
        if (!el) return undefined
        if (!lockPlay) {
          const promise = el.play()
          const isPromise = typeof promise === 'object'
          if (isPromise) {
            lockPlay = true
            const resetLock = () => {
              lockPlay = false
            }
            promise.then(resetLock)
          }

          return promise
        }
        return undefined
      },
      pause: () => {
        const el = element.el
        if (!el) return undefined
        if (el && !lockPlay) {
          return el.pause()
        }
      },
      seek: (time: number) => {
        const el = element.el
        if (!el) return undefined
        state.duration = el.duration
        time = Math.min(1, Math.max(0, time))
        isChange = true
        console.log('执行。。。')
        el.currentTime = state.duration * time
        setTimeout(() => {
          isChange = false
        }, 100)
      },
      volume: (volume: number) => {
        const el = element.el
        if (!el) {
          return
        }
        volume = Math.min(1, Math.max(0, volume))
        state.volume = el.volume = volume
      },
    }
    watch(
      musicUrl,
      () => {
        const el = element.el
        if (!el) {
          if (import.meta.env.MODE !== 'production') {
            if (tag === 'audio') {
              console.error(
                'useAudio() ref to <audio> element is empty at mount. ' +
                  'It seem you have not rendered the audio element, which it ' +
                  'returns as the first argument const [audio] = useAudio(...).',
              )
            } else if (tag === 'video') {
              console.error(
                'useVideo() ref to <video> element is empty at mount. ' +
                  'It seem you have not rendered the video element, which it ' +
                  'returns as the first argument const [video] = useVideo(...).',
              )
            }
          }
          return
        }
        el.src = musicUrl.value
        state.muted = el.muted
        state.paused = el.paused
        if (el.paused) {
          controls.play()
        }
      },
      {
        deep: true,
      },
    )

    return [element, state, controls]
  }
  return hook
}

export default createHTMLMediaHook
